package com.develop;

import com.develop.data.loan.manager.L0001B0001LoanClearManager;
import com.develop.data.loan.manager.L0001B0001LoanRepaymentManager;
import com.develop.data.loan.manager.L0001B0001LoanRepaymentPlanManager;
import com.develop.data.loan.manager.api.LoanRepaymentManager;
import com.develop.data.loan.manager.api.LoanRepaymentPlanManager;
import com.develop.data.loan.manager.change.amount.L0001B0001LoanInstallmentInterestBudget;
import com.develop.data.loan.manager.change.amount.L0001B0001LoanInstallmentPrincipalBudget;
import com.develop.data.loan.manager.change.transfer.LoanContractCommonToCleared;
import com.develop.data.loan.manager.change.transfer.LoanInstallmentCommonToCleared;
import com.develop.data.loan.model.LoanContract;
import com.develop.data.loan.model.LoanInstallment;
import com.develop.data.loan.model.LoanRepayment;
import com.develop.data.loan.option.*;
import com.develop.data.loan.repository.LoanContractRepository;
import com.develop.data.loan.repository.LoanInstallmentRepository;
import com.develop.data.loan.repository.LoanRepaymentRepository;
import lombok.extern.slf4j.Slf4j;
import org.javamoney.moneta.Money;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.money.Monetary;
import javax.money.MonetaryAmount;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;


@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest1 {

    @Autowired
    LoanContractRepository loanContractRepository;

    @Autowired
    LoanInstallmentRepository loanInstallmentRepository;

    @Autowired
    LoanRepaymentRepository loanRepaymentRepository;


    public static void main( String[] args )
    {
        SpringApplication.run(Application.class, args);
    }


    @Test
    public void test() throws Exception {

        log.info("新建合约对象");
        LoanContract contract;
        String contractId = UUID.randomUUID().toString().replace("-","");
        contract = LoanContract.builder()
                .loanUsage(LoanUsage.CONSUMPTION)
                .loanCorpusType(LoanCorpusType.EQUAL_CORPUS_ON_SCHEDULE)
                .loanState(LoanState.ENCASH_SUCCEED)
                .contractEncashAmount(Money.of(1200, "CNY"))
                .contractTermHead(1)
                .contractTermTail(6)
                .contractValueDate(LocalDateTime.of(2022,2,10,0,0,0))
                .loanTimelineType(LoanTimelineType.FIX_DAY)
                .contractRepaymentDay(10)
                .loanRateType(LoanRateType.FIXED_DAILY)
                .contractRateValue("0.0004")
                .contractFirstTermDaysFloor(15)
                .loanInstallments(new ArrayList<>())
                .loanRepayments(new ArrayList<>())
                .build();


        log.info("计算分期对象");
        
        LoanRepaymentPlanManager loanContractManager = new L0001B0001LoanRepaymentPlanManager(contract);

        List<LoanInstallment> installments = loanContractManager.getRepaymentPlan();
        /*installments.forEach(installment->{
            String installmentId = UUID.randomUUID().toString().replace("-","");
            installment.setId(installmentId);
        });*/
        contract.setLoanInstallments(installments);
        contract = loanContractRepository.saveAndFlush(contract);

        LoanInstallment firstInstallment = contract.getLoanInstallments().get(0);


        LoanRepaymentManager repaymentManager = new L0001B0001LoanRepaymentManager();
        repaymentManager.previewInstallmently(installments.get(0), LocalDate.of(2022, 2, 10).atStartOfDay());

        log.info("2022/2/10，预算期次应还利息");
        log.info(
                new L0001B0001LoanInstallmentInterestBudget().preview(
                        firstInstallment,
                        LocalDate.of(2022, 2, 10).atStartOfDay()
                ).toString()
        );
        log.info("2022/2/10，预算期次应还本金");
        log.info(
                new L0001B0001LoanInstallmentPrincipalBudget().preview(
                        firstInstallment,
                        LocalDate.of(2022, 2, 10).atStartOfDay()
                ).toString()
        );

        log.info("2022/2/10，还款100元，首期还款顺序，先还利息，再还本金");

        LoanRepayment repayment = LoanRepayment.builder()
                .loanContract(contract)
                .cursor(LocalDate.of(2022, 2, 10).atStartOfDay())
                .repaymentAmount(Money.of(100, "CNY"))
                .build();


        List<LoanRepayment> repayments =  contract.getLoanRepayments();
        repayments.add(repayment);
        //contract.setLoanRepayments(repayments);
        contract = loanContractRepository.saveAndFlush(contract);


        //loanContractRepository.saveAndFlush(contract);
        //loanContractRepository.save(contract);

        List<String> amountNames = new ArrayList<String>() {{
            add("installmentInterestAccrual");
            add("installmentPrincipalDueAccrual");
        }};

        MonetaryAmount repaymentAmount = repayment.getRepaymentAmount();
        MonetaryAmount residueAmount = repaymentAmount;
        for (String amountName:amountNames) {
            switch (amountName) {
                case "installmentInterestAccrual":
                    residueAmount = new L0001B0001LoanInstallmentInterestBudget().execute(
                            firstInstallment,
                            LocalDate.of(2022, 2, 10).atStartOfDay(),
                            repaymentAmount
                    );
                    repayment.setInstallmentInterest(repaymentAmount.subtract(residueAmount));
                    repaymentAmount = residueAmount;
                    break;
                case "installmentPrincipalDueAccrual":
                    residueAmount = new L0001B0001LoanInstallmentPrincipalBudget().execute(
                            firstInstallment,
                            LocalDate.of(2022, 2, 10).atStartOfDay(),
                            repaymentAmount
                    );
                    repayment.setInstallmentPrincipal(repaymentAmount.subtract(residueAmount));
                    repaymentAmount = residueAmount;
                    break;
                default:
                    throw new RuntimeException("Unknown Amount!");
            }
            if (repaymentAmount.isEqualTo(Money.zero(Monetary.getCurrency("CNY")))) {
                break;
            }
        }

        contract = loanContractRepository.save(contract);



        log.info("2022/2/10，还款100元后，立即再次预算期次应还利息");
        log.info(
                new L0001B0001LoanInstallmentInterestBudget().preview(
                        firstInstallment,
                        LocalDate.of(2022, 2, 10).atStartOfDay()
                ).toString()
        );
        log.info("2022/2/10，还款100元后，立即再次预算期次应还本金");
        log.info(
                new L0001B0001LoanInstallmentPrincipalBudget().preview(
                        firstInstallment,
                        LocalDate.of(2022, 2, 10).atStartOfDay()
                ).toString()
        );

        installments = contract.getLoanInstallments();


        log.info("2022/2/10，预算期次结清");
        log.info(
                new LoanInstallmentCommonToCleared().preview(
                        firstInstallment,
                        LocalDate.of(2022, 2, 10).atStartOfDay()
                ).toString()
        );

        log.info("2022/2/10，预算合约结清");
        log.info(
                new LoanContractCommonToCleared().preview(
                        contract,
                        LocalDate.of(2022, 2, 10).atStartOfDay()
                ).toString()
        );

        log.info("2022/2/10，期次结清");
        new LoanInstallmentCommonToCleared().execute(
                firstInstallment,
                LocalDate.of(2022, 2, 10).atStartOfDay()
        );

        log.info("2022/2/10，合约结清");
        new LoanContractCommonToCleared().execute(
                contract,
                LocalDate.of(2022, 2, 10).atStartOfDay()
        );

        contract = loanContractRepository.save(contract);


        log.info("结束");

    }
}